package net.sf.odinms.exttools.doclet.pages;

import java.io.IOException;
import java.util.List;
import java.util.Vector;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.ExecutableMemberDoc;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.ProgramElementDoc;
import com.sun.tools.doclets.internal.toolkit.util.DeprecatedAPIListBuilder;
import net.sf.odinms.exttools.doclet.AbstractPageWriter;
import net.sf.odinms.exttools.doclet.Doclet;

/**
 * Creates "deprecated.html", a listing of all deprecated components.
 */
@SuppressWarnings("unchecked")
public final class DeprecatedList extends AbstractPageWriter {
	
	/** A structure containing all deprecated elements being documented. */
	private DeprecatedAPIListBuilder deprecatedAPI;
	
	/**
	 * Names to use for section anchors from nav links within this page. Doubles
	 * as the keys for localized names in the doclet properties file.
	 */
	private static final String[] ANCHORS =
			new String[] {"Interfaces", "Classes", "Enums", "Exceptions",
					"Errors", "Annotation_Types", "Fields", "Methods",
					"Constructors", "Enum_Constants", "Annotation_Type_Members"};
	
	/**
	 * Generation page containing deprecated symbols. Exits without creating if
	 * {@link net.sf.odinms.exttools.doclet.Config#nodeprecatedlist CONF.nodeprecatedlist}
	 * is true.
	 */
	public static void generateDeprecatedList() {
		if (CONF.nodeprecatedlist)
			return;
		String filename = "deprecated-list" + CONF.ext;
		try {
			new DeprecatedList(filename);
		}
		catch (IOException exc) {
			throw Doclet.exception(exc, filename);
		}
	}
	
	/**
	 * Initialize filename and page type for list of deprecated symbols.
	 * 
	 * @param filename The desired name of the file (with extension).
	 * @throws IOException If {@link java.io.FileOutputStream} creation fails.
	 */
	private DeprecatedList(String filename) throws IOException {
		super(filename);
		pageType = PageType.DEPRECATED;
		deprecatedAPI = new DeprecatedAPIListBuilder(CONF.root);
		
		windowTitle =
				(CONF.windowtitle.length() > 0)
						? CONF.windowtitle
						: CONF.propertyText("Deprecated_List");
		
		printXhtmlHeader();
		
		println(open("h1") + CONF.propertyText("Deprecated_List") + close("h1"));
		
		println(openDivWithID("Summaries"));
		
		String[] headingKeys =
				new String[] {"Deprecated_Interfaces", "Deprecated_Classes",
						"Deprecated_Enums", "Deprecated_Exceptions",
						"Deprecated_Errors", "Deprecated_Annotation_Types",
						"Deprecated_Fields", "Deprecated_Methods",
						"Deprecated_Constructors", "Deprecated_Enum_Constants",
						"Deprecated_Annotation_TypeMembers"};
		
		for (int type = 0; type < DeprecatedAPIListBuilder.NUM_TYPES; type++) {
			if (deprecatedAPI.hasDocumentation(type)) {
				println(new TagBuilder("h2").add("id", ANCHORS[type]).getOpenTextClose(
						CONF.propertyText(headingKeys[type])));
				// anchor(ANCHORS[type]);
				// writers[i].printDeprecatedAPI(deprecatedAPI.getList(i),
				// HEADING_KEYS[i]);
				// This method is in AbstractMemberWriter.java
				printDeprecatedAPI(deprecatedAPI.getList(type),
						headingKeys[type]);
			}
		}
		println(close("div") + getComment("Summaries"));
		
		printXhtmlFooter();
		this.close();
	}
	
	/**
	 * Generate the code for listing the deprecated APIs. Create the table
	 * format for listing the API. Call methods from the sub-class to complete
	 * the generation.
	 * 
	 * @param deprMembers A list of deprecated members of the current type.
	 * @param headingKey The localized string key to use for this header.
	 */
	// TODO Sort deprecated items by fully qualified name.
	// TODO Use fast iterators rather than for loop?
	private void printDeprecatedAPI(List deprMembers, String headingKey) {
		if (deprMembers.size() > 0) {
			println(open("dl"));
			for (int i = 0; i < deprMembers.size(); i++) {
				ProgramElementDoc member =
						(ProgramElementDoc) deprMembers.get(i);
				print(open("dt"));
				// All this is just to rebuild the fully-qualified name with
				// bolding.
				String label =
						(member instanceof ClassDoc)
								? member.containingPackage().toString()
								: member.containingClass().toString();
				label += "." + bold(member.name());
				if (member instanceof ExecutableMemberDoc) {
					List<String> params = new Vector<String>();
					for (Parameter param : ((ExecutableMemberDoc) member).parameters()) {
						// TODO Be sure to properly handle parameterized types.
						params.add(param.typeName());
					}
					label += "(" + getJoinedStrings(params, ", ") + ")";
				}
				// Cannot be a package, so hrefToDoc() always returns full path.
				println(linkToLabelHref(label, hrefToDoc(member)));
				println(close("dt"));
				// If deprecation detail comments are supplied, print them here.
				print(open("dd"));
				if (member.tags("deprecated").length > 0
						&& member.tags("deprecated")[0].inlineTags().length > 0)
					print(getCommentTagsString(member,
							member.tags("deprecated")[0].inlineTags(), false,
							false));
				println(close("dd"));
			}
			println(close("dl"));
		}
	}
	
	/** Highlight "Deprecated" as current section, don't create link. */
	protected void navLinkDeprecated() {
		println(listItemCurrent(DEPRECATED));
	}
	
	/** Print links to Summary sections for various types of elements. */
	protected void navWithinPage() {
		
		// Links to package-level and class-level sections within document
		List<String> sections = new Vector<String>();
		for (int type = 0; type < DeprecatedAPIListBuilder.NUM_TYPES; type++) {
			if (deprecatedAPI.hasDocumentation(type)) {
				sections.add(linkToLabelHref(
						CONF.propertyText(ANCHORS[type]), "#"
								+ ANCHORS[type]));
			}
		}
		// To get only the package-level elements, iterate to:
		// type <= DeprecatedAPIListBuilder.ANNOTATION_TYPE
		// For class-level, continue after that to < NUM_TYPES
		print(open("td id=\"WithinPage\""));
		printUnorderedListWithLast(sections);
		println(close("td"));
	}
	
}
